80. 构建

80.1 生成构建信息

Maven和Gradle都支持产生包含项目版本,坐标,名称的构建信息,该插件可以通过配置添加其他属性。当这些文件出现时,Spring Boot自动配置一个BuildProperties bean。

为了让Maven生成构建信息,你需要为build-info goal添加一个execution:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>1.4.1.RELEASE</version>
            <executions>
                <execution>
                    <goals>
                        <goal>build-info</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

更多详情查看Spring Boot Maven插件文档

使用Gradle实现同样效果:

springBoot  {
    buildInfo()
}

可以使用DSL添加其他属性:

springBoot  {
    buildInfo {
        additionalProperties = [
            'foo': 'bar'
        ]
    }
}

80.2 生成Git信息

Maven和Gradle都支持生成一个git.properties文件,该文件包含项目构建时git源码的仓库状态。对于Maven用户来说,spring-boot-starter-parent POM包含一个预配置的插件去产生一个git.properties文件,只需简单的将以下声明添加到POM中:

<build>
    <plugins>
        <plugin>
            <groupId>pl.project13.maven</groupId>
            <artifactId>git-commit-id-plugin</artifactId>
        </plugin>
    </plugins>
</build>

Gradle用户可以使用gradle-git-properties插件实现相同效果:

plugins {
    id "com.gorylenko.gradle-git-properties" version "1.4.6"
}

80.3 自定义依赖版本

如果你使用Maven进行一个直接或间接继承spring-boot-dependencies(比如spring-boot-starter-parent)的构建,并想覆盖一个特定的第三方依赖,那你可以添加合适的<properties>元素。浏览spring-boot-dependencies POM可以获取一个全面的属性列表。例如,想要选择一个不同的slf4j版本,你可以添加以下内容:

<properties>
    <slf4j.version>1.7.5<slf4j.version>
</properties>

这只在你的Maven项目继承(直接或间接)自spring-boot-dependencies才有用。如果你使用<scope>import</scope>,将spring-boot-dependencies添加到自己的dependencyManagement片段,那你必须自己重新定义artifact而不是覆盖属性。

每个Spring Boot发布都是基于一些特定的第三方依赖集进行设计和测试的,覆盖版本可能导致兼容性问题。

Gradle中为了覆盖依赖版本,你需要指定如下所示的version:

ext['slf4j.version'] = '1.7.5'

更多详情查看Gradle Dependency Management插件文档

80.4 使用Maven创建可执行JAR

spring-boot-maven-plugin能够用来创建可执行的'胖'JAR。如果正在使用spring-boot-starter-parent POM,你可以简单地声明该插件,然后你的jar将被重新打包:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

如果没有使用parent POM,你仍旧可以使用该插件。不过,你需要另外添加一个<executions>片段:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>1.4.1.RELEASE</version>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

查看插件文档获取详细的用例。

80.5 将Spring Boot应用作为依赖

跟war包一样,Spring Boot应用不是用来作为依赖的。如果你的应用包含需要跟其他项目共享的类,最好的方式是将代码放到单独的模块,然后其他项目及你的应用都可以依赖该模块。

如果不能按照上述推荐的方式重新组织代码,你需要配置Spring Boot的Maven和Gradle插件去产生一个单独的artifact,以适合于作为依赖。可执行存档不能用于依赖,因为可执行jar格式将应用class打包到BOOT-INF/classes,也就意味着可执行jar用于依赖时会找不到。

为了产生两个artifacts(一个用于依赖,一个用于可执行jar),你需要指定classifier。classifier用于可执行存档的name,默认存档用于依赖。

可以使用以下配置Maven中classifier的exec

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <classifier>exec</classifier>
            </configuration>
        </plugin>
    </plugins>
</build>

使用Gradle可以添加以下配置:

bootRepackage  {
    classifier = 'exec'
}

80.6 在可执行jar运行时提取特定的版本

在一个可执行jar中,为了运行,多数内嵌的库不需要拆包(unpacked),然而有一些库可能会遇到问题。例如,JRuby包含它自己的内嵌jar,它假定jruby-complete.jar本身总是能够直接作为文件访问的。

为了处理任何有问题的库,你可以标记那些特定的内嵌jars,让它们在可执行jar第一次运行时自动解压到一个临时文件夹中。例如,为了将JRuby标记为使用Maven插件拆包,你需要添加如下的配置:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <requiresUnpack>
                    <dependency>
                        <groupId>org.jruby</groupId>
                        <artifactId>jruby-complete</artifactId>
                    </dependency>
                </requiresUnpack>
            </configuration>
        </plugin>
    </plugins>
</build>

使用Gradle完全上述操作:

springBoot  {
    requiresUnpack = ['org.jruby:jruby-complete']
}

80.7 使用排除创建不可执行的JAR

如果你构建的产物既有可执行的jar和非可执行的jar,那你常常需要为可执行的版本添加额外的配置文件,而这些文件在一个library jar中是不需要的。比如,application.yml配置文件可能需要从非可执行的JAR中排除。

下面是如何在Maven中实现:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <classifier>exec</classifier>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-jar-plugin</artifactId>
            <executions>
                <execution>
                    <id>exec</id>
                    <phase>package</phase>
                    <goals>
                        <goal>jar</goal>
                    </goals>
                    <configuration>
                        <classifier>exec</classifier>
                    </configuration>
                </execution>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>jar</goal>
                    </goals>
                    <configuration>
                        <!-- Need this to ensure application.yml is excluded -->
                        <forceCreation>true</forceCreation>
                        <excludes>
                            <exclude>application.yml</exclude>
                        </excludes>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

在Gradle中,你可以使用标准任务的DSL(领域特定语言)特性创建一个新的JAR存档,然后在bootRepackage任务中使用withJarTask属性添加对它的依赖:

jar {
    baseName = 'spring-boot-sample-profile'
    version =  '0.0.0'
    excludes = ['**/application.yml']
}

task('execJar', type:Jar, dependsOn: 'jar') {
    baseName = 'spring-boot-sample-profile'
    version =  '0.0.0'
    classifier = 'exec'
    from sourceSets.main.output
}

bootRepackage  {
    withJarTask = tasks['execJar']
}

80.8 远程调试使用Maven启动的Spring Boot项目

想要为使用Maven启动的Spring Boot应用添加一个远程调试器,你可以使用mave插件的jvmArguments属性,详情参考示例

80.9 远程调试使用Gradle启动的Spring Boot项目

想要为使用Gradle启动的Spring Boot应用添加一个远程调试器,你可以使用build.gradleapplicationDefaultJvmArgs属性或--debug-jvm命令行选项。

build.gradle:

applicationDefaultJvmArgs = [
    "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005"
]

命令行:

$ gradle run --debug-jvm

详情查看Gradle应用插件

80.10 使用Ant构建可执行存档(不使用spring-boot-antlib)

想要使用Ant进行构建,你需要抓取依赖,编译,然后像通常那样创建一个jar或war存档。为了让它可以执行,你可以使用spring-boot-antlib,也可以使用以下指令:

  1. 如果构建jar,你需要将应用的类和资源打包进内嵌的BOOT-INF/classes目录。如果构建war,你需要将应用的类打包进内嵌的WEB-INF/classes目录。
  2. 对于jar,添加运行时依赖到内嵌的BOOT-INF/lib目录。对于war,则添加到WEB-INF/lib目录。注意不能压缩存档中的实体。
  3. 对于jar,添加provided依赖到内嵌的BOOT-INF/lib目录。对于war,则添加到WEB-INF/lib-provided目录。注意不能压缩存档中的实体。
  4. 在存档的根目录添加spring-boot-loader类(这样Main-Class就可用了)。
  5. 使用恰当的启动器,比如对于jar使用JarLauncher作为manifest的Main-Class属性,指定manifest的其他属性,特别是Start-Class

示例:

<target name="build" depends="compile">
    <jar destfile="target/${ant.project.name}-${spring-boot.version}.jar" compress="false">
        <mappedresources>
            <fileset dir="target/classes" />
            <globmapper from="*" to="BOOT-INF/classes/*"/>
        </mappedresources>
        <mappedresources>
            <fileset dir="src/main/resources" erroronmissingdir="false"/>
            <globmapper from="*" to="BOOT-INF/classes/*"/>
        </mappedresources>
        <mappedresources>
            <fileset dir="${lib.dir}/runtime" />
            <globmapper from="*" to="BOOT-INF/lib/*"/>
        </mappedresources>
        <zipfileset src="${lib.dir}/loader/spring-boot-loader-jar-${spring-boot.version}.jar" />
        <manifest>
            <attribute name="Main-Class" value="org.springframework.boot.loader.JarLauncher" />
            <attribute name="Start-Class" value="${start-class}" />
        </manifest>
    </jar>
</target>

Ant示例中有一个build.xml文件及manual任务,可以使用以下命令来运行:

$ ant -lib <folder containing ivy-2.2.jar> clean manual

在上述操作之后,你可以使用以下命令运行该应用:

$ java -jar target/*.jar

80.11 如何使用Java6

如果想在Java6环境中使用Spring Boot,你需要改变一些配置,具体的改变取决于你应用的功能。

80.11.1 内嵌Servlet容器兼容性

如果你在使用Boot的内嵌Servlet容器,你需要使用一个兼容Java6的容器。Tomcat 7和Jetty 8都是Java 6兼容的。具体参考Section 70.16 使用Tomcat 7.x或8.0Section 70.18 使用Jetty 8

80.11.2 Jackson

Jackson 2.7及以后版本需要Java 7,如果想要在Java 6环境使用Jackson,你需要降级使用Jackson 2.6。

80.11.3 JTA API兼容性

虽然Java Transaction API自身不要求Java 7,但官方API jar包含的已构建类需要Java 7。如果正在使用JTA,你需要使用能够在Java 6环境工作的jar替换官方的JTA 1.2 API jar。想要实现这样的效果,你需要排除任何javax.transaction:javax.transaction-api依赖,并使用org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.0.0.Final替换它。